package com.lianjia.crawler;

import com.lianjia.crawler.model.HouseInfo;
import com.lianjia.crawler.parser.HouseParser;
import com.lianjia.crawler.utils.DataLoader;
import com.lianjia.crawler.utils.FileUtils;
import com.lianjia.crawler.utils.HttpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 链家爬虫主类
 */
public class Main {
    private static final Logger logger = LoggerFactory.getLogger(Main.class);
    private static final Pattern PAGE_RANGE_PATTERN = Pattern.compile("^\\D*(\\d+)\\D+(\\d+)\\D*$");
    private static final int MAX_RETRY = 100000000; // 最大重试次数
    
    public static void main(String[] args) {
        try {
            logger.info("链家爬虫启动");
            System.out.println("链家爬虫启动");
            
            
            // 加载城市代码和用户代理
            DataLoader.loadCityCodes();
            DataLoader.loadUserAgents();
            
            // 获取用户输入的城市名或拼音
            Scanner scanner = new Scanner(System.in);
            System.out.print("请输入城市名或拼音代码: ");
            String cityInput = scanner.nextLine().trim();
            
            // 获取城市代码和城市名
            String[] cityInfo = DataLoader.getCityCodeByPinyinOrName(cityInput);
            if (cityInfo == null) {
                logger.error("链家暂未提供该城市相关信息，请检查输入是否正确");
                System.out.println("链家暂未提供该城市相关信息，请检查输入是否正确");
                return;
            }
            
            String cityCode = cityInfo[0];
            String cityName = cityInfo[1];
            
            System.out.println("已选择城市: " + cityName + " (代码: " + cityCode + ")");
            
            // 获取用户输入的页数范围
            System.out.print("请输入页数范围: ");
            String pageRangeInput = scanner.nextLine().trim();
            Matcher matcher = PAGE_RANGE_PATTERN.matcher(pageRangeInput);
            
            int left, right;
            if (matcher.find()) {
                left = Integer.parseInt(matcher.group(1));
                right = Integer.parseInt(matcher.group(2));
                
                if (left < 1 || left > right || right > 100) {
                    logger.error("页数范围不合法");
                    System.out.println("页数范围不合法");
                    return;
                }
            } else {
                logger.error("输入格式不合法");
                System.out.println("输入格式不合法");
                return;
            }
            
            // 开始爬取数据
            List<HouseInfo> allInfos = new ArrayList<>();
            
            for (int page = left; page <= right; page++) {
                // 构建页面URL
                String url = String.format("https://%s.lianjia.com/ershoufang/pg%d/", cityCode, page);
                String referer = String.format("https://%s.lianjia.com/ershoufang/", cityCode);
                
                // 获取随机用户代理
                String userAgent = DataLoader.getRandomUserAgent();
                
                // 获取页面HTML
                logger.info("正在爬取第 {} 页...", page);
                System.out.println("正在爬取第 " + page + " 页...");
                List<HouseInfo> pageInfos = null;
                
                // 不断尝试，直到成功解析出数据或达到最大重试次数
                int retryCount = 0;
                while (pageInfos == null && retryCount < MAX_RETRY) {
                    String html = HttpUtils.getHtml(url, userAgent, referer);
                    
                    // 每次请求使用新的User-Agent
                    userAgent = DataLoader.getRandomUserAgent();
                    
                    if (html != null) {
                        pageInfos = HouseParser.parseHouseList(html);
                    }
                    
                    if (pageInfos == null) {
                        retryCount++;
                        logger.warn("第 {} 次尝试解析失败，正在重试...", retryCount);
                        System.out.println("第 " + retryCount + " 次尝试解析失败，正在重试...");
                        
                        // 如果多次尝试失败，可能是被反爬机制拦截，等待更长时间
                        if (retryCount >= 5) {
                            logger.warn("多次尝试失败，可能是被反爬机制拦截，等待时间增加");
                            System.out.println("多次尝试失败，可能是被反爬机制拦截，等待时间增加");
                            try {
                                Thread.sleep(10000 + retryCount * 2000);
                            } catch (InterruptedException e) {
                                Thread.currentThread().interrupt();
                            }
                        }
                    }
                }
                
                if (pageInfos == null) {
                    logger.error("第 {} 页爬取失败，已达到最大重试次数", page);
                    System.out.println("第 " + page + " 页爬取失败，已达到最大重试次数");
                    continue; // 跳过这一页，继续爬取下一页
                }
                
                // 下载并保存图片
                logger.info("正在保存第 {} 页的图片...", page);
                System.out.println("正在保存第 " + page + " 页的图片...");
                for (HouseInfo info : pageInfos) {
                    String imageUrl = info.getImage();
                    if (imageUrl != null && !imageUrl.trim().isEmpty()) {
                        String localImagePath = FileUtils.saveImage(imageUrl, cityCode, userAgent);
                        info.setImage(localImagePath);
                    }
                }
                
                // 添加到总列表
                allInfos.addAll(pageInfos);
                logger.info("第 {} 页爬取完成，当前共有 {} 条数据", page, allInfos.size());
                System.out.println("第 " + page + " 页爬取完成，当前共有 " + allInfos.size() + " 条数据");
            }
            
            if (allInfos.isEmpty()) {
                logger.error("未爬取到任何数据");
                System.out.println("未爬取到任何数据");
                return;
            }
            
            // 保存结果
            logger.info("正在保存爬取结果...");
            System.out.println("正在保存爬取结果...");
            FileUtils.saveResults(allInfos, cityName, left, right);
            
            // 打开结果文件夹
            try {
                File resultDir = new File("result/information");
                if (resultDir.exists() && Desktop.isDesktopSupported()) {
                    Desktop.getDesktop().open(resultDir);
                }
            } catch (IOException e) {
                logger.warn("无法自动打开结果文件夹", e);
            }
            
            logger.info("爬取完成，共获取 {} 条房源信息", allInfos.size());
            System.out.println("爬取完成，共获取 " + allInfos.size() + " 条房源信息");
            System.out.println("结果已保存到 result/information 文件夹");
            
        } catch (Exception e) {
            logger.error("爬虫运行出错", e);
            System.out.println("爬虫运行出错: " + e.getMessage());
            e.printStackTrace();
        }
    }
} 